﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace KDG.FoldersSize.Scaner
{
    /// <remarks>
    /// Класс для сканирования дерева диска
    /// </remarks>
    public class Scanner
    {
        private bool _cancelled = false;
        private BackgroundWorker bwScan = null;

        /// <summary>
        /// Сканирует дерево поддиректорий по заданному пути.
        /// Создает список (дерево).
        /// </summary>
        /// <param name="Path">Путь начала сканирования</param>
        /// <param name="Sort">Флаг сортировки</param>
        /// <returns>Возвращает вершину дерева</returns>
        public ScannerItem Scan(string Path)
        {
            ScannerItem ret = ScanDirectory(new ScannerItem(Path, Path));
            ret.CalcPprogressTotal(ret.Length);
            return ret;
        }
        private ScannerItem ScanDirectory(ScannerItem Directory)
        {
            if (bwScan != null && bwScan.CancellationPending) { _cancelled = true; return Directory; }
            if (bwScan != null) { bwScan.ReportProgress(0, Directory.FullName); }

            DirectoryInfo di = new DirectoryInfo(Directory.FullName);
            try
            {
                FileInfo[] fis = di.GetFiles();
                foreach (FileInfo file in fis)
                {
                    Directory.Childs.Add(
                        new ScannerItem(file.Name, file.FullName) 
                                { IsDirectory = false, Length = file.Length }
                        );
                    Directory.Length += file.Length;
                }
                Directory.FilesCount += fis.Length;

                DirectoryInfo[] dis = di.GetDirectories();
                foreach (DirectoryInfo dir in dis)
                {
                    ScannerItem si = new ScannerItem(dir.Name, dir.FullName) { IsDirectory = true };
                    Directory.Childs.Add(si);
                    ScanDirectory(si);

                    Directory.Length += si.Length;
                    Directory.FilesCount += si.FilesCount;
                    Directory.FoldersCount += si.FoldersCount;
                }
                Directory.FoldersCount += dis.Length;

                Directory.CalcPprogress();

                Directory.SortChilds();
            }
            catch (UnauthorizedAccessException) { }
            //catch (Exception ex) { throw ex; }
            finally { }

            return Directory;
        }
        /// <summary>
        /// Запускает сканирование директории по указанному пути асинхронно.
        /// Включает поддиректории
        /// </summary>
        /// <param name="Path">Путь начала сканирования</param>
        public void ScanAsync(string Path)
        {
            bwScan = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };

            bwScan.DoWork += new DoWorkEventHandler(bwScan_DoWork);
            bwScan.ProgressChanged += new ProgressChangedEventHandler(bwScan_ProgressChanged);
            bwScan.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwScan_RunWorkerCompleted);

            bwScan.RunWorkerAsync(Path);
        }
        /// <summary>
        /// Останавливает сканирование асинхронно
        /// </summary>
        public void CancelAsync()
        {
            if (bwScan != null)
                bwScan.CancelAsync();
        }
        private void bwScan_DoWork(object sender, DoWorkEventArgs e)
        {
                e.Result = Scan(e.Argument as string);
        }
        private void bwScan_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (ProgressChanged != null)
                ProgressChanged(sender, e);
        }
        private void bwScan_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (RunWorkerCompleted != null)
            {
                if (e.Error != null)
                    RunWorkerCompleted(sender,
                        new RunWorkerCompletedEventArgs(null, e.Error, this._cancelled));
                else
                    RunWorkerCompleted(sender,
                        new RunWorkerCompletedEventArgs(e.Result, e.Error, this._cancelled));
            }
        }
        /// <summary>
        /// Возникает при смене директории сканирования
        /// </summary>
        public event ProgressChangedEventHandler ProgressChanged;
        /// <summary>
        /// Возникает при завершении сканирования по всей глубине
        /// </summary>
        public event RunWorkerCompletedEventHandler RunWorkerCompleted;
    }
}
